/*
 *  mmu.c
 *  
 *
 *  Created by Rayvionne French on 7/2/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

#include "mmu.h"

//-------------------------------------------------------------------
//  MMU Class
//  NOTE: This class does not use a lock internally. A lock should be
//  used whenever using this class to perform an operation or sequence
//  of operations.
// -------------------------------------------------------------------


MMU::MMU(Machine* systemMachine) {
	ipt = new VMTranslationEntry[NumPhysPages];
	machine = systemMachine;
	iptEntries = 0;
	pageQueue = new List();
}

MMU::~MMU() {
	delete [] ipt;
	delete pageQueue;
}

void MMU::iptSetEntry(VMTranslationEntry* from) {
	//printf("On iptSet Dirty[%d]\n", from->dirty);
	int index = from->physicalPage;
	ipt[index].physicalPage = from->physicalPage;
	ipt[index].virtualPage = from->virtualPage;
	ipt[index].valid = from->valid;
	ipt[index].dirty = from->dirty;
	ipt[index].use = from->use;
	ipt[index].readOnly = from->readOnly;
	ipt[index].processID = from->processID;
	ipt[index].pageType = from->pageType;
	ipt[index].location = from->location;
	ipt[index].offset = from->offset;
	iptEntries++;
	pageQueue->Append((void*)ipt[index].physicalPage);
}

VMTranslationEntry* MMU::iptGetEviction() {
	int pageToEvict = rand() % NumPhysPages;
	//pageToEvict->inUse = TRUE;
	//int pageToEvict = (int)pageQueue->Remove();
	iptEntries--;
	return &ipt[pageToEvict];
}

VMTranslationEntry* MMU::iptGetEntry(int index) {
	return &ipt[index];
}

void MMU::iptSetDirty(int ppn, bool dirty) {
	ipt[ppn].dirty = dirty;
}
//-------------------------------------------------------------------
//  MMU:iptFind
//  This method looks for the translation entry match in the IPT with
//  the given virtual page number and process ID. It returns the index
//  of the matching entry. If there is no match, it returns -1.
// -------------------------------------------------------------------
int MMU::iptFind(int vpn, int processID) {
	int i;
	for(i=0; i<NumPhysPages; i++) {
		if(vpn == ipt[i].virtualPage && processID == ipt[i].processID) {
			if(ipt[i].valid)
				return i;
		}
	}
	return -1;
}

// -------------------------------------------------------------------
//  MMU:iptClearProcess
//  This method invalidates all translation entries with the given
//  processID.
// -------------------------------------------------------------------
void MMU::iptClearProcess(int processID) {
	int i,j;
	for(i=0; i<NumPhysPages; i++) {
		if(processID == ipt[i].processID && ipt[i].valid == TRUE) {
			ipt[i].valid = FALSE;
		}
	}
}

// -------------------------------------------------------------------
//  MMU:iptClearPage
//  This method invalidates the translation entry with the given
//  physical page number and process ID.
// -------------------------------------------------------------------
void MMU::iptClearPage(int ppn, int processID) {
	int i;
	for(i=0; i<NumPhysPages; i++) {
		if(ppn == ipt->physicalPage && processID == ipt->processID) {
			ipt[i].valid = FALSE;
		}
	}
}

// -------------------------------------------------------------------
//  MMU:iptClearAt
//  This method invalidates the translation entry with the given
//  index and process ID.
// -------------------------------------------------------------------
void MMU::iptClearAt(int index, int processID) {
	if(ipt[index].processID == processID)
		ipt[index].valid = FALSE;
}
